package mya_dc.slave;

import java.io.File;
import java.net.Socket;
import java.util.LinkedList;

import mya_dc.shared_classes.CompilationErrors;
import mya_dc.shared_classes.CompilationFlags;
import mya_dc.shared_classes.MYA_File;
import mya_dc.shared_classes.Message;
import mya_dc.shared_classes.Transmitter;
import mya_dc.shared_classes.files_manipulation.FileObject;
import mya_dc.shared_classes.SharedDefinitions;

/**
 * Handles a compilation request from a compilation server
 *
 * <p>
 * <b>Notes:</b>
 * <ul>
 * <li>Class uses CompilationPackage class to do the compilation.
 * <li>Class sends two messages back to compilation server:
 * <br>(1) Compilation errors (or no errors message).
 * <br>(2) Object result files (Or no object result files message).
 * </ul>
 * <p>
 * 
 * @author      Yuval Shimron
 * <br>			MYA
 */

class SlaveThread extends Thread {
	
	private String m_strWorkingDir;
	private Socket m_sktNum;
	private Slave m_Parent;
	public boolean abort;
	
	/**
	 * Constructor
	 *
	 * @param	strWorkingDir - The root of the package.
	 * @param 	sktNum - compilation server's socket.
	 * @param	Parent - The parent class
	 */
	public SlaveThread(String strWorkingDir, Socket sktNum, Slave Parent)
	{
		super();
		abort = false;
		m_strWorkingDir = strWorkingDir;
		m_sktNum = sktNum;
		m_Parent = Parent;
	}
	
	/**
	 * Thread's first called function 
	 * <br>
	 * <br>Receives files to the working directory, compiles them and sends back errors and result object files
	 *
	 */
	public void run()
	{
		Message resMessage = new Message(Message.EMessageType.FILE_TRANSFER, null);
		Transmitter transPackage = null;
		CompilationFlags compFlags = null;
		
		try	{
			transPackage = new Transmitter(m_sktNum, m_strWorkingDir + "\\", SharedDefinitions.SecsBetweenTwoKeepAliveMessages);
			while (resMessage.getType() != Message.EMessageType.FILE_TRANSFER_NO_MORE_FILES)
			{
				resMessage = transPackage.receive();
				if (resMessage.getType() != Message.EMessageType.FILE_TRANSFER &&
					resMessage.getType() != Message.EMessageType.FILE_TRANSFER_NO_MORE_FILES)
				{
					terminate();
				}
			}
			compFlags = (CompilationFlags)resMessage.getObject();
		}
		catch(Exception e) {
			terminate();
		}
		
		// handles package (building *.o file and sending back)
		CompilationPackage Package = new CompilationPackage(m_strWorkingDir, compFlags);

		MYA_File objDir = null;
		
		try {
			if (abort) terminate();
			CompilationErrors errors = Package.doCppCompilation();
			if (abort) terminate();
			if (!errors.isEmpty()) // no errors
				transPackage.send(new Message(
					Message.EMessageType.COMPILATION_RESULT_ERRORS,
					errors
					)
				);
			else 
				transPackage.send(new Message(
					Message.EMessageType.COMPILATION_RESULT_NO_ERRORS,
					null
					)
				);
			
			objDir = new MYA_File(m_strWorkingDir);
			File[] tmpList = ((File)objDir).listFiles();
			LinkedList<MYA_File> resList = new LinkedList<MYA_File>();
			
			// creates a MYA_File object list (we have to know how many object files exists)
			for (File file : tmpList)
			{
				String filename = file.getName();
				String ext = (filename.lastIndexOf(".") == -1 )? "": filename.substring(filename.lastIndexOf(".")+1,filename.length());
				if (ext.equals("o"))
					resList.add(new MYA_File(file));
			}
				
			if (abort) 
				terminate();
			if (resList.isEmpty())
			{
				transPackage.send(new Message(
					Message.EMessageType.FILE_TRANSFER_NO_OBJECT_FILES,
					null
					)
				);
			}
			else
			{
				// creates a MYA_File array to be sent back
				Object[] objList = resList.toArray();
				MYA_File[] myaList = new MYA_File[objList.length];
				for (int i = 0 ; i < objList.length ; i++)
				{
					myaList[i] = (MYA_File)objList[i];
				}
				transPackage.setWorkingDirectory(m_strWorkingDir + "-res\\");
				if (abort) terminate();
				transPackage.send(new Message(
					Message.EMessageType.FILE_TRANSFER_OBJECT_FILES,
					myaList
					)
				);
				transPackage.receive();			}
		}
		catch(Exception e)
		{ 
			/* ignored - slave doesn't handle communication errors issues with servers */
		}
		terminate();
	}
	
	/**
	 * Terminates the thread
	 *
	 */
	void terminate()
	{
		try { m_sktNum.close(); } catch (Exception ee) {}
		m_Parent.removeThread(this);
		FileObject.deleteDirectory(new File(m_strWorkingDir + "-res\\"));
		FileObject.deleteDirectory(new File(m_strWorkingDir));
	}
}